/* drv-ssd1963.c

   written by Armin Schlegel
   25 February 2014

   Copyright (C) 2014 Armin Schlegel

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   version 2 as published by the Free Software Foundation.
   Please refer to the file debian/copyright for further details.

   -----------
   DESCRIPTION
   -----------

*/

#include <apex.h>
#include <config.h>
#include <driver.h>
#include <service.h>
#include <command.h>
#include <error.h>
#include <linux/string.h>
#include <asm/reg.h>
#include <linux/kernel.h>

#include <mach/hardware.h>
#include <mach/drv-ssd1963.h>

#define DRIVER_NAME  "lcd-ssd1963"

struct ssd1963 {
  volatile u16* ctrl;
  volatile u16* data;
};

static struct ssd1963 ssd1963;

static void ssd1963_send_cmd(SSD1963_u16 cmd)
{
   *ssd1963.ctrl = 0x00FF & cmd;
}

static void ssd1963_send_data(u16 data)
{
   *ssd1963.ctrl = data;
}

//static u16 ssd1963_read_data()
//{
//  int value;
//  value =  *ssd1963.data;
//  DBG (3, "%s: %x\n", __FUNCTION__, value);
//  return value;
//}

static void ssd1963_set_window(u16 xs, u16 xe, u16 ys, u16 ye)
{
   ssd1963_send_cmd(SSD1963_SET_COLUMN_ADDRESS);
   ssd1963_send_data((xs >> 8) & 0x00FF);
   ssd1963_send_data(xs & 0x00FF);
   ssd1963_send_data((xe  >> 8 ) & 0x00FF);
   ssd1963_send_data(xe & 0x00FF);

   ssd1963_send_cmd(SSD1963_SET_PAGE_ADDRESS);
   ssd1963_send_data((ys >> 8) & 0x00FF);
   ssd1963_send_data(ys & 0x00FF);
   ssd1963_send_data((ye  >> 8 ) & 0x00FF);
   ssd1963_send_data(ye & 0x00FF);

   ssd1963_send_cmd(SSD1963_WRITE_MEMORY_START);
}


static void ssd1963_init (void)
{
   u32 cnt;
   ssd1963.ctrl = &__REG16 (SSD_PHYS_CTRL);
   ssd1963.data  = &__REG16 (SSD_PHYS_DATA);

   GPIO_OUT_LOW(IOCONF_GPIO, _BIT(13)); //GPIO19 is nRESET
   udelay(200000);
   GPIO_OUT_HIGH(IOCONF_GPIO, _BIT(13)); //GPIO19 is nRESET
   udelay(200000);

   GPIO_OUT_HIGH(IOCONF_GPIO, _BIT(14)); //GPIO20 is LED_ENABLE


   ssd1963_send_cmd(SSD1963_SET_PLL); // PLL config - continued
   ssd1963_send_data(0x0001);

   ssd1963_send_cmd(SSD1963_SET_PLL_MN); // PLL config - continued
   ssd1963_send_data(0x002D);
   ssd1963_send_data(0x0002);
   ssd1963_send_data(0x0004);


   ssd1963_send_cmd(SSD1963_SET_PLL); // PLL config - continued
   ssd1963_send_data(0x0003);
   udelay(100000);


   ssd1963_send_cmd(SSD1963_SOFT_RESET);
   udelay(10000);

   ssd1963_send_cmd(SSD1963_SET_LSHIFT_FREQ);
   ssd1963_send_data(0x0000); // LSHIFT freq
   ssd1963_send_data(0x00FF);
   ssd1963_send_data(0x00BE);

   ssd1963_send_cmd(SSD1963_SET_LCD_MODE);
   ssd1963_send_data(0x0020);  // set lcd mode
   ssd1963_send_data(0x0000);
   ssd1963_send_data(0x0001);
   ssd1963_send_data(0x00DF);
   ssd1963_send_data(0x0001);
   ssd1963_send_data(0x0017);
   ssd1963_send_data(0x0000);
   udelay(5000);

   ssd1963_send_cmd(SSD1963_SET_HORI_PERIOD);
   ssd1963_send_data(0x0002);  // horizontal period
   ssd1963_send_data(0x000D);
   ssd1963_send_data(0x0000);
   ssd1963_send_data(0x0028);
   ssd1963_send_data(0x0027);
   ssd1963_send_data(0x0000);
   ssd1963_send_data(0x0006);
   ssd1963_send_data(0x0000);

   ssd1963_send_cmd(SSD1963_SET_VERT_PERIOD);
   ssd1963_send_data(0x0001); // vertical period
   ssd1963_send_data(0x0020);
   ssd1963_send_data(0x0000);
   ssd1963_send_data(0x000C);
   ssd1963_send_data(0x000B);
   ssd1963_send_data(0x0000);
   ssd1963_send_data(0x0008);

   ssd1963_send_cmd(SSD1963_SET_ADDRESS_MODE);
   ssd1963_send_data(0x0000);  // rotation - landscape

   ssd1963_send_cmd(SSD1963_SET_PIXEL_DATA_INTERFACE);
   ssd1963_send_data(0x0003);  // pixel data interface 16 bit    0b011 is 16 Bit
   udelay(5000);

   ssd1963_send_cmd(SSD1963_SET_DISPLAY_ON); // set display on

   ssd1963_send_cmd(SSD1963_SET_PWM_CONF);
   ssd1963_send_data(0x0006);  // pwm config
   ssd1963_send_data(0x00F0);
   ssd1963_send_data(0x0001);
   ssd1963_send_data(0x00F0);
   ssd1963_send_data(0x0000);
   ssd1963_send_data(0x0000);

   ssd1963_send_cmd(SSD1963_SET_DBC_CONF);
   ssd1963_send_data(0x000D); // pwm coffig continued

   ssd1963_send_cmd(SSD1963_SET_GPIO_CONF);
   ssd1963_send_data(0x0000); // gpio config
   ssd1963_send_data(0x0000);

   ssd1963_send_cmd(SSD1963_SET_GPIO_VALUE);
   ssd1963_send_data(0x0000); // gpio to 0x00

   ssd1963_set_window(0, 0, SCREENWIDTH, SCREENHEIGHT);

   for(cnt = 0; cnt < SSD1963_SCREENSIZE; cnt++)
   {
      ssd1963_send_data(SSD1963_DEFAULT_COLOR);
   }

}



static __driver_4 struct driver_d ssd1963_driver = {
  .name = DRIVER_NAME,
  .description = "Solomon Systech SSD1963 LCD driver",
  .flags = DRIVER_LCD,
};

static __service_6 struct service_d ssd1963_service = {
  .init = ssd1963_init,
#endif
};

